/*
 * @Descripttion: 
 * @version: 
 * @Author: 马琳峰
 * @Date: 2020-09-29 11:00:33
 * @LastEditors: 马琳峰
 * @LastEditTime: 2020-09-30 09:11:31
 */
// 作业 

//一、将下面异步代码使用 Promise的方式改进
setTimeout(function(){
    var a = "hellow";
    setTimeout(function(){
        var b = "lagou";
        setTimeout(function(){
            var c = "I ❤ U";
            // console.log(a + b +c);
        })
    })
});


function timeOut (text){
    return new Promise((resolve,reject)=>{
        setTimeout(()=>{
            resolve(text);
        },10);
    })
}

timeOut("hellow").then(res => {
    return timeOut(res + "lagou");
}).then(res=>{
    return timeOut(res + "I ❤ U");
}).then(res => {
    console.log(res);
});

// 二、基于以下代码完成下面四个练习
const fp = require("lodash/fp");
/** 
 * 数据
 * horspower 马力
 * dollar_value 价格
 * in_stock 库存
*/
const cars = [ 
    { name: 'Ferrari FF', horsepower: 660, dollar_value: 700000, in_stock: true }, 
    { name: 'Spyker C12 Zagato', horsepower: 650, dollar_value: 648000, in_stock: false }, 
    { name: 'Jaguar XKR‐S', horsepower: 550, dollar_value: 132000, in_stock: false },
    { name: 'Audi R8', horsepower: 525, dollar_value: 114200, in_stock: false },
    { name: 'Aston Martin One‐ 77', horsepower: 750, dollar_value: 1850000, in_stock: true }, 
    { name: 'Pagani Huayra', horsepower: 700, dollar_value: 1300000, in_stock: false }
]

// 练习1： 使用函数组合fp.flowRight() 重新实现下面这个函数
let isLastInStock = function (cars) { 
    //获取最后一条数据 
    let last_car = fp.last(cars);
    //获取最后一条数据的 in_stock 属性值 
    return fp.prop('in_stock', last_car);
}

console.log(isLastInStock(cars));

let newLast = fp.flowRight(fp.prop("in_stock"),fp.last);

console.log(newLast(cars));


//练习2：使用fp.flowRight()、fp.prop()和fp.first 获取第一个car的name

let getFirstCarName = fp.flowRight(fp.prop("name"),fp.first);
console.log(getFirstCarName(cars));


//练习3： 使用帮助函数_average重构 averageDollarValue，使用函数组合方式实现

let _average = function (xs) { 
    return fp.reduce(fp.add, 0, xs) / xs.length;
} // <‐ 无须改动

let averageDollarValue = function(array){
     let saveItem =  function (arr){
        let count = fp.map(function (car) { 
            return car.dollar_value
        }, arr);

        return count;
    }

    return fp.flowRight(_average,saveItem)(array);
};

let getAverage = averageDollarValue(cars);

console.log(getAverage);

/**  
 * 练习4：使用flowRight 写一个sanitizeNames() 函数，
 * 返回一个下划线链接的小写字符串，把数组中的name转换为这种形式： 例如 
 * 写一个sanitizeNames(["Hello World"]) => ['hellow world'] 
 * **/
let _underscore = fp.replace(/\W+/g,"_");//无需改动并在函数中使用她

function sanitizeNames(array){
    return fp.flowRight(fp.map(_underscore),fp.map(fp.toLower))(array);
}

console.log(sanitizeNames(['Hello World',"DLFJADLFJDLSFSFJ","DFSFDSFDF"]));


//三、基于下面提供的代码，完成后续的四个练习

const { Maybe, Container } = require("./support.js");

//练习1： 使用fp.add(x,y) 和 fp.map(f,x) 创建一个能让functor里的值增加的函数 ex1
let maybe = Maybe.of([5, 6, 1]);
let ex1 = (num) => {  
    //你需要实现的函数...
    let fn = fp.flowRight(fp.map(fp.add(num)));
    return maybe.map(fn);
}
console.log(ex1(1));

//练习2： 实现一个函数ex2 能够使用fp.first获取列表的第一个元素
let xs = Container.of([
    "do",
    "ray",
    "me",
    "fa",
    "so",
    "la",
    "ti",
    "do"
])
let ex2 = () => {
    return xs.map(fp.first)._value
}

console.log(ex2());

//练习3： 实现一个函数ex3 使用safeProp 和 fp.first 找到user 的名字首字目
let safeProp = fp.curry(function (x, o) {
    return Maybe.of(o[x])
})
let user = { id: 2, name: 'Albert' }

let ex3 = () => {
    //你需要实现的函数...
    return  safeProp("name")(user).map(fp.first)._value;
}
console.log(ex3());

//练习4： 使用Maybe 重写ex4 不要有if语句

let ex4 = function (n){
    if(n){
        return parseInt(n);
    }
}

let myEx4 = function(n){
    return Maybe.of(n).map(parseInt)._value;
}

console.log(myEx4(4645.12313));


//四、 手写实现MyPromise源码
//要求： 尽可能还原Promise中的每一个API, 并通过注释的方式描述思路和原理
const PENDING = "pending"; //等待
const PULFILLED = "pulfilled"; //成功
const REJECTED = "rejected";//失败

class myPromise{
    constructor(executr){
        try{
            executr(this.resolve,this.reject);
        }
        catch(err){
            this.reject(err);
        }
    }
    //成功之后的值
    value = undefined;
    //失败之后的原因
    reason = undefined;
    // Promise状态
    status = PENDING;
    //成功回调
    successCallback = [];
    //失败回调
    failCallback = [];
    //修改成功状态
    resolve = value =>{
        //如果状态不是等待直接退出函数
        if(this.status !== PENDING) return;
        this.status = PULFILLED;
        //设置成功后的值
        this.value = value;

        //this.successCallback && this.successCallback(value);
        while(this.successCallback.length){
            this.successCallback.shift()();
        }
    }
    //修改状态失败
    reject = value => {
        //如果状态不是等待直接退出函数
        if(this.status !== PENDING) return;
        this.status = REJECTED;
        //设置失败后的原因
        this.reason = value;

        //this.failCallback && this.failCallback(value);
        while(this.failCallback.length){
            this.failCallback.shift()();
        }
    }
    finally(callback){
        return this.then(value=>{
            return myPromise.resolve(callback()).then(()=> value)
        },err=>{
            return myPromise.resolve(callback()).then(()=> {throw err}) 
        })
    }
    then = (successCallback,failCallback)=>{
        
        successCallback = successCallback ? successCallback : value=>value;
        failCallback = failCallback ? failCallback : err=> {throw err};

        let promise2 = new myPromise((reslove,reject)=>{
            if(this.status == PULFILLED){
                //异步 为了能够获取到 promise2
                setTimeout(()=>{
                   try{
                        let x = successCallback(this.value);
                        //判断x是普通值还是promise对象
                        //如果是普通值直接调用resolve
                        //如果是promise对象，查看promise对象返回的结果
                        //在根据promise对象返回的结果 决定调用resolve 还是reject
                        resolvePromise(promise2,x,reslove,reject);
                   }
                   catch(err){
                        reject(err);
                   }
                },0);
            }else if(this.status == REJECTED){
                setTimeout(()=>{
                    try{
                        let x = failCallback(this.reason);
                        //判断x是普通值还是promise对象
                        //如果是普通值直接调用resolve
                        //如果是promise对象，查看promise对象返回的结果
                        //在根据promise对象返回的结果 决定调用resolve 还是reject
                        resolvePromise(promise2,x,reslove,reject);
                    }
                    catch(err){
                        reject(err);
                    }
                 },0);
            }else{
                //等待
                //将成功回调和失败回调存储起来
                this.successCallback.push(()=>{
                    setTimeout(()=>{
                        try{
                            let x = successCallback(this.value);
                            //判断x是普通值还是promise对象
                            //如果是普通值直接调用resolve
                            //如果是promise对象，查看promise对象返回的结果
                            //在根据promise对象返回的结果 决定调用resolve 还是reject
                            resolvePromise(promise2,x,reslove,reject);
                        }
                        catch(err){
                            reject(err);
                        }
                    },0)
                });
                this.failCallback.push(()=>{
                    setTimeout(()=>{
                        try{
                            let x = failCallback(this.reason);
                            //判断x是普通值还是promise对象
                            //如果是普通值直接调用resolve
                            //如果是promise对象，查看promise对象返回的结果
                            //在根据promise对象返回的结果 决定调用resolve 还是reject
                            resolvePromise(promise2,x,reslove,reject);
                        }
                        catch(err){
                            reject(err);
                        }
                    },0)
                });
            }
        });
        return promise2;
    }
    catch(failCallback){
        return  this.then(undefined,failCallback)
    }
    //注意需要在所有promise异步执行之后调用reslove
    static all (array){
        //结果数组
        let result = [];
        let index = 0;
        
        return new myPromise((reslove,reject)=>{
            function addData (i,value){
                result[i] = value;
                index++;
                if(index === array.length){
                    reslove(result);
                }
            }
            for(let i=0;i<array.length;i++){
                let current = array[i];
                if(current instanceof myPromise){
                    //promise对象
                    current.then(value=>{
                        addData(i,value)
                    },err=>{
                        reject(err)
                    });
                }else{
                    //普通值
                    addData(i,current);
                }
            }
        })
    }
    static resolve(data){
        if(data instanceof myPromise){
            return data;
        }else{
            return new myPromise((resolve,reject)=>{
                resolve(data);
            })
        }
    }
}
function resolvePromise (promise2,x,reslove,reject){
    //判断返回
    if(promise2 === x){
        return reject(new TypeError("promise对象被循环调用"))
    }
    //判断是否是promise对象
    if(x instanceof myPromise) {
        // x.then(value=> resolve(value),err=>reject(err));
        //简写
        x.then(reslove,reject);
    }else{
        reslove(x);
    }
}